/**
 * 1114. 按序打印
 * https://leetcode-cn.com/problems/print-in-order/
 */
public class Solutions_1114 {
    public static void main(String[] args) {
        try {
            Foo obj = new Foo();

            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        obj.first(new Runnable() {
                            @Override
                            public void run() {
                                System.out.println("first");
                            }
                        });
                    } catch(InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        obj.second(new Runnable() {
                            @Override
                            public void run() {
                                System.out.println("second");
                            }
                        });
                    } catch(InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            Thread t3 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        obj.third(new Runnable() {
                            @Override
                            public void run() {
                                System.out.println("third");
                            }
                        });
                    } catch(InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });

            t3.start();
            t2.start();
            t1.start();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

/**
 * synchronized 实现
 */
class Foo {
    private volatile int flag = 1;
    private Object obj = new Object();

    public Foo() {

    }

    public void first(Runnable printFirst) throws InterruptedException {
        synchronized(obj) {
            while (flag != 1) {
                obj.wait();
            }
            // printFirst.run() outputs "first". Do not change or remove this line.
            printFirst.run();
            flag += 1;
            obj.notifyAll();
        }
    }

    public void second(Runnable printSecond) throws InterruptedException {
        synchronized(obj) {
            while (flag != 2) {
                // 等待线程 1 执行完
                obj.wait();
            }
            // printSecond.run() outputs "second". Do not change or remove this line.
            printSecond.run();
            flag += 1;
            obj.notifyAll();
        }
    }

    public void third(Runnable printThird) throws InterruptedException {
        synchronized(obj) {
            while (flag != 3) {
                // 等待线程 2 执行完
                obj.wait();
            }
            // printThird.run() outputs "third". Do not change or remove this line.
            printThird.run();
            flag += 1;
            obj.notifyAll();
        }
    }
}
